home *** CD-ROM | disk | FTP | other *** search
/ Aminet 30 / Aminet 30 (1999)(Schatztruhe)[!][Apr 1999].iso / Aminet / gfx / misc / gnuplot-3.7src.lha / gnuplot-3.7src / gnuplot-3.7.lha / gnuplot-3.7 / gplt_x11.c < prev    next >
C/C++ Source or Header  |  1998-12-15  |  50KB  |  1,716 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: gplt_x11.c,v 1.71 1998/04/14 00:15:22 drd Exp $";
  3. #endif
  4.  
  5. /* GNUPLOT - gplt_x11.c */
  6.  
  7. /*[
  8.  * Copyright 1986 - 1993, 1998   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted,
  12.  * provided that the above copyright notice appear in all copies and
  13.  * that both that copyright notice and this permission notice appear
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the complete modified source code.  Modifications are to
  18.  * be distributed as patches to the released version.  Permission to
  19.  * distribute binaries produced by compiling modified sources is granted,
  20.  * provided you
  21.  *   1. distribute the corresponding source modifications from the
  22.  *    released version in the form of a patch file along with the binaries,
  23.  *   2. add special version identification to distinguish your version
  24.  *    in addition to the base release version number,
  25.  *   3. provide your name and address as the primary contact for the
  26.  *    support of your modified version, and
  27.  *   4. retain our contact information in regard to use of the base
  28.  *    software.
  29.  * Permission to distribute the released version of the source code along
  30.  * with corresponding source modifications in the form of a patch file is
  31.  * granted with same provisions 2 through 4 for binary distributions.
  32.  *
  33.  * This software is provided "as is" without express or implied warranty
  34.  * to the extent permitted by applicable law.
  35. ]*/
  36.  
  37.  
  38. /* lph changes:
  39.  * (a) make EXPORT_SELECTION the default and specify NOEXPORT to undefine
  40.  * (b) append X11 terminal number to resource name
  41.  * (c) change cursor for active terminal
  42.  */
  43.  
  44. /*-----------------------------------------------------------------------------
  45.  *   gnuplot_x11 - X11 outboard terminal driver for gnuplot 3.3
  46.  *
  47.  *   Requires installation of companion inboard x11 driver in gnuplot/term.c
  48.  *
  49.  *   Acknowledgements: 
  50.  *      Chris Peterson (MIT)
  51.  *      Dana Chee (Bellcore) 
  52.  *      Arthur Smith (Cornell)
  53.  *      Hendri Hondorp (University of Twente, The Netherlands)
  54.  *      Bill Kucharski (Solbourne)
  55.  *      Charlie Kline (University of Illinois)
  56.  *      Yehavi Bourvine (Hebrew University of Jerusalem, Israel)
  57.  *      Russell Lang (Monash University, Australia)
  58.  *      O'Reilly & Associates: X Window System - Volumes 1 & 2
  59.  *
  60.  *   This code is provided as is and with no warranties of any kind.
  61.  *
  62.  * drd: change to allow multiple windows to be maintained independently
  63.  *       
  64.  * There is a mailing list for gnuplot users. Note, however, that the
  65.  * newsgroup 
  66.  *    comp.graphics.apps.gnuplot 
  67.  * is identical to the mailing list (they
  68.  * both carry the same set of messages). We prefer that you read the
  69.  * messages through that newsgroup, to subscribing to the mailing list.
  70.  * (If you can read that newsgroup, and are already on the mailing list,
  71.  * please send a message to majordomo@dartmouth.edu, asking to be
  72.  * removed from the mailing list.)
  73.  *
  74.  * The address for mailing to list members is
  75.  *       info-gnuplot@dartmouth.edu
  76.  * and for mailing administrative requests is 
  77.  *       majordomo@dartmouth.edu
  78.  * The mailing list for bug reports is 
  79.  *       bug-gnuplot@dartmouth.edu
  80.  * The list of those interested in beta-test versions is
  81.  *       info-gnuplot-beta@dartmouth.edu
  82.  *---------------------------------------------------------------------------*/
  83.  
  84. /* drd : export the graph via ICCCM primary selection. well... not quite
  85.  * ICCCM since we dont support full list of targets, but this
  86.  * is a start.  define EXPORT_SELECTION if you want this feature
  87.  */
  88.  
  89. /*lph: add a "feature" to undefine EXPORT_SELECTION
  90.    The following makes EXPORT_SELECTION the default and 
  91.    defining NOEXPORT over-rides the default
  92.  */
  93.  
  94. #ifdef HAVE_CONFIG_H
  95. # include "config.h"
  96. #endif
  97.  
  98. #ifdef EXPORT_SELECTION
  99. # undef EXPORT_SELECTION
  100. #endif /* EXPORT SELECTION */
  101. #ifndef NOEXPORT
  102. # define EXPORT_SELECTION XA_PRIMARY
  103. #endif /* NOEXPORT */
  104.  
  105.  
  106. #if !(defined(VMS) || defined(CRIPPLED_SELECT))
  107. # define DEFAULT_X11
  108. #endif
  109.  
  110. #if defined(VMS) && defined(CRIPPLED_SELECT)
  111. Error. Incompatible options.
  112. #endif
  113.  
  114.  
  115. #include <X11/Xos.h>
  116. #include <X11/Xlib.h>
  117. #include <X11/Xresource.h>
  118. #include <X11/Xutil.h>
  119. #include <X11/Xatom.h>
  120. #include <X11/keysym.h>
  121.  
  122. #include <signal.h>
  123.  
  124. #ifdef HAVE_SYS_BSDTYPES_H
  125. # include <sys/bsdtypes.h>
  126. #endif /* HAVE_SYS_BSDTYPES_H */
  127.  
  128. #ifdef __EMX__
  129. /* for gethostname ... */
  130. # include <netdb.h>
  131. #endif
  132.  
  133. #if defined(HAVE_SYS_SELECT_H) && !defined(VMS)
  134. # include <sys/select.h>
  135. #endif /* HAVE_SYS_SELECT_H && !VMS */
  136.  
  137. #ifndef FD_SET
  138. # define FD_SET(n, p)    ((p)->fds_bits[0] |= (1 << ((n) % 32)))
  139. # define FD_CLR(n, p)    ((p)->fds_bits[0] &= ~(1 << ((n) % 32)))
  140. # define FD_ISSET(n, p)  ((p)->fds_bits[0] & (1 << ((n) % 32)))
  141. # define FD_ZERO(p)      memset((char *)(p),'\0',sizeof(*(p)))
  142. #endif /* not FD_SET */
  143.  
  144. #include "plot.h"
  145.  
  146. #if defined(HAVE_SYS_SYSTEMINFO_H) && defined(HAVE_SYSINFO)
  147. # include <sys/systeminfo.h>
  148. # define SYSINFO_METHOD "sysinfo"
  149. # define GP_SYSTEMINFO(host) sysinfo (SI_HOSTNAME, (host), MAXHOSTNAMELEN)
  150. #else
  151. # define SYSINFO_METHOD "gethostname"
  152. # define GP_SYSTEMINFO(host) gethostname ((host), MAXHOSTNAMELEN)
  153. #endif /* HAVE_SYS_SYSTEMINFO_H && HAVE_SYSINFO */
  154.  
  155. #ifdef VMS
  156. # ifdef __DECC
  157. #  include <starlet.h>
  158. # endif                /* __DECC */
  159. # define EXIT(status) sys$delprc(0,0)    /* VMS does not drop itself */
  160. #else
  161. # define EXIT(status) exit(status)
  162. #endif
  163.  
  164. #ifdef OSK
  165. # define EINTR    E_ILLFNC
  166. #endif
  167.  
  168. /* information about one window/plot */
  169.  
  170. typedef struct plot_struct {
  171.     Window window;
  172.     Pixmap pixmap;
  173.     unsigned int posn_flags;
  174.     int x, y;
  175.     unsigned int width, height;    /* window size */
  176.     unsigned int px, py;    /* pointsize */
  177.     int ncommands, max_commands;
  178.     char **commands;
  179. } plot_struct;
  180.  
  181. void store_command __PROTO((char *line, plot_struct * plot));
  182. void prepare_plot __PROTO((plot_struct * plot, int term_number));
  183. void delete_plot __PROTO((plot_struct * plot));
  184.  
  185. int record __PROTO((void));
  186. void process_event __PROTO((XEvent * event));    /* from Xserver */
  187.  
  188. void mainloop __PROTO((void));
  189.  
  190. void display __PROTO((plot_struct * plot));
  191.  
  192. void reset_cursor __PROTO((void));
  193.  
  194. void preset __PROTO((int argc, char *argv[]));
  195. char *pr_GetR __PROTO((XrmDatabase db, char *resource));
  196. void pr_color __PROTO((void));
  197. void pr_dashes __PROTO((void));
  198. void pr_font __PROTO((void));
  199. void pr_geometry __PROTO((void));
  200. void pr_pointsize __PROTO((void));
  201. void pr_width __PROTO((void));
  202. Window pr_window __PROTO((unsigned int flags, int x, int y, unsigned int width, unsigned height));
  203. void pr_raise __PROTO((void));
  204. void pr_persist __PROTO((void));
  205.  
  206. #ifdef EXPORT_SELECTION
  207. void export_graph __PROTO((plot_struct * plot));
  208. void handle_selection_event __PROTO((XEvent * event));
  209. #endif
  210.  
  211. #define FallbackFont "fixed"
  212.  
  213. #define Ncolors 13
  214. unsigned long colors[Ncolors];
  215.  
  216. #define Nwidths 10
  217. unsigned int widths[Nwidths] = { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  218.  
  219. #define Ndashes 10
  220. char dashes[Ndashes][5];
  221.  
  222. #define MAX_WINDOWS 16
  223.  
  224. #define XC_crosshair 34
  225.  
  226.  
  227. struct plot_struct plot_array[MAX_WINDOWS];
  228.  
  229.  
  230. Display *dpy;
  231. int scr;
  232. Window root;
  233. Visual *vis;
  234. GC gc = (GC) 0;
  235. XFontStruct *font;
  236. int do_raise = 1, persist = 0;
  237. KeyCode q_keycode;
  238. Cursor cursor;
  239.  
  240. int windows_open = 0;
  241.  
  242. int gX = 100, gY = 100;
  243. unsigned int gW = 640, gH = 450;
  244. unsigned int gFlags = PSize;
  245.  
  246. unsigned int BorderWidth = 2;
  247. unsigned int D;            /* depth */
  248.  
  249. Bool Mono = 0, Gray = 0, Rv = 0, Clear = 0;
  250. char Name[64] = "gnuplot";
  251. char Class[64] = "Gnuplot";
  252.  
  253. int cx = 0, cy = 0, vchar;
  254. double xscale, yscale, pointsize;
  255. #define X(x) (int) ((x) * xscale)
  256. #define Y(y) (int) ((4095-(y)) * yscale)
  257.  
  258. #define Nbuf 1024
  259. char buf[Nbuf], **commands = (char **) 0;
  260.  
  261. FILE *X11_ipc;
  262. char X11_ipcpath[32];
  263.  
  264. /* when using an ICCCM-compliant window manager, we can ask it
  265.  * to send us an event when user chooses 'close window'. We do this
  266.  * by setting WM_DELETE_WINDOW atom in property WM_PROTOCOLS
  267.  */
  268.  
  269. Atom WM_PROTOCOLS, WM_DELETE_WINDOW;
  270.  
  271. XPoint Diamond[5], Triangle[4];
  272. XSegment Plus[2], Cross[2], Star[4];
  273.  
  274. /*-----------------------------------------------------------------------------
  275.  *   main program 
  276.  *---------------------------------------------------------------------------*/
  277.  
  278. int main(argc, argv)
  279. int argc;
  280. char *argv[];
  281. {
  282.  
  283.  
  284. #ifdef OSK
  285.     /* malloc large blocks, otherwise problems with fragmented mem */
  286.     _mallocmin(102400);
  287. #endif
  288. #ifdef __EMX__
  289.     /* close open file handles */
  290.     fcloseall();
  291. #endif
  292.  
  293.     FPRINTF((stderr, "gnuplot_X11 starting up\n"));
  294.  
  295.     preset(argc, argv);
  296.  
  297. /* set up the alternative cursor */
  298.     cursor = XCreateFontCursor(dpy, XC_crosshair);
  299.  
  300.     mainloop();
  301.  
  302.     if (persist) {
  303.     FPRINTF((stderr, "waiting for %d windows\n, windows_open"));
  304.     /* read x events until all windows have been quit */
  305.     while (windows_open > 0) {
  306.         XEvent event;
  307.         XNextEvent(dpy, &event);
  308.         process_event(&event);
  309.     }
  310.     }
  311.     XCloseDisplay(dpy);
  312.  
  313.     FPRINTF((stderr, "exiting\n"));
  314.  
  315.     EXIT(0);
  316. }
  317.  
  318. /*-----------------------------------------------------------------------------
  319.  *   mainloop processing - process X events and input from gnuplot
  320.  *
  321.  *   Three different versions of main loop processing are provided to support
  322.  *   three different platforms.
  323.  * 
  324.  *   DEFAULT_X11:     use select() for both X events and input on stdin 
  325.  *                    from gnuplot inboard driver
  326.  *
  327.  *   CRIPPLED_SELECT: use select() to service X events and check during 
  328.  *                    select timeout for temporary plot file created
  329.  *                    by inboard driver
  330.  *
  331.  *   VMS:             use XNextEvent to service X events and AST to
  332.  *                    service input from gnuplot inboard driver on stdin 
  333.  *---------------------------------------------------------------------------*/
  334.  
  335.  
  336. #ifdef DEFAULT_X11
  337. /*-----------------------------------------------------------------------------
  338.  *    DEFAULT_X11 mainloop
  339.  *---------------------------------------------------------------------------*/
  340.  
  341. void mainloop()
  342. {
  343.     int nf, nfds, cn = ConnectionNumber(dpy), in;
  344.     struct timeval *timer = (struct timeval *) 0;
  345. #ifdef ISC22
  346.     struct timeval timeout;
  347. #endif
  348.     fd_set rset, tset;
  349.  
  350.     X11_ipc = stdin;
  351.     in = fileno(X11_ipc);
  352.  
  353.     FD_ZERO(&rset);
  354.     FD_SET(cn, &rset);
  355.  
  356.     FD_SET(in, &rset);
  357.     nfds = (cn > in) ? cn + 1 : in + 1;
  358.  
  359. #ifdef ISC22
  360. /* Added by Robert Eckardt, RobertE@beta.TP2.Ruhr-Uni-Bochum.de */
  361.     timeout.tv_sec = 0;        /* select() in ISC2.2 needs timeout */
  362.     timeout.tv_usec = 300000;    /* otherwise input from gnuplot is */
  363.     timer = &timeout;        /* suspended til next X event. */
  364. #endif /* ISC22   (0.3s are short enough not to be noticed */
  365.  
  366.     while (1) {
  367.  
  368.     /* XNextEvent does an XFlush() before waiting. But here.
  369.      * we must ensure that the queue is flushed, since we
  370.      * dont call XNextEvent until an event arrives. (I have
  371.      * twice wasted quite some time over this issue, so now
  372.      * I am making sure of it !
  373.      */
  374.  
  375.     XFlush(dpy);
  376.  
  377.     tset = rset;
  378.     nf = select((gp_nfds_t)nfds, gp_fd_set_p &tset, gp_fd_set_p 0,
  379.              gp_fd_set_p 0, gp_timeval_p timer);
  380.     if (nf < 0) {
  381.         if (errno == EINTR)
  382.         continue;
  383.         fprintf(stderr, "gnuplot: select failed. errno:%d\n", errno);
  384.         EXIT(1);
  385.     }
  386.     if (nf > 0)
  387.         XNoOp(dpy);
  388.  
  389.     if (FD_ISSET(cn, &tset)) {
  390.         /* used to use CheckMaskEvent() but that cannot receive
  391.          * maskable events such as ClientMessage. So now we do
  392.          * one event, then return to the select.
  393.          * And that almost works, except that under some Xservers
  394.          * running without a window manager (e.g. Hummingbird Exceed under Win95)
  395.          * a bogus ConfigureNotify is sent followed by a valid ConfigureNotify
  396.          * when the window is maximized.  The two events are queued, apparently
  397.          * in a single I/O because select() above doesn't see the second, valid
  398.          * event.  This little loop fixes the problem by flushing the
  399.          * event queue completely.
  400.          */
  401.         XEvent xe;
  402.         do {
  403.         XNextEvent(dpy, &xe);
  404.         process_event(&xe);
  405.         } while (XPending(dpy));
  406.     }
  407.     if (FD_ISSET(in, &tset)) {
  408.         if (!record())      /* end of input */
  409.         return;
  410.     }
  411.     }
  412. }
  413.  
  414. #endif
  415.  
  416.  
  417. #ifdef CRIPPLED_SELECT
  418. /*-----------------------------------------------------------------------------
  419.  *    CRIPPLED_SELECT mainloop
  420.  *---------------------------------------------------------------------------*/
  421.  
  422. void mainloop()
  423. {
  424.     int nf, nfds, cn = ConnectionNumber(dpy);
  425.     struct timeval timeout, *timer;
  426.     fd_set rset, tset;
  427.     unsigned long all = (unsigned long) (-1L);
  428.     XEvent xe;
  429.  
  430.     FD_ZERO(&rset);
  431.     FD_SET(cn, &rset);
  432.  
  433.     timeout.tv_sec = 1;
  434.     timeout.tv_usec = 0;
  435.     timer = &timeout;
  436.     sprintf(X11_ipcpath, "/tmp/Gnuplot_%d", getppid());
  437.     nfds = cn + 1;
  438.  
  439.     while (1) {
  440.     XFlush(dpy);        /* see above */
  441.     tset = rset;
  442.     nf = select((gp_nfds_t)nfds, gp_fd_set_p &tset, gp_fd_set_p 0,
  443.             gp_fd_set_p 0, gp_timeval_p timer);
  444.     if (nf < 0) {
  445.         if (errno == EINTR)
  446.         continue;
  447.         fprintf(stderr, "gnuplot: select failed. errno:%d\n", errno);
  448.         EXIT(1);
  449.     }
  450.     nf > 0 && XNoOp(dpy);
  451.     if (FD_ISSET(cn, &tset)) {
  452.         while (XCheckMaskEvent(dpy, all, &xe)) {
  453.         process_event(&xe);
  454.         }
  455.     }
  456.     if ((X11_ipc = fopen(X11_ipcpath, "r"))) {
  457.         unlink(X11_ipcpath);
  458.         record();
  459.         fclose(X11_ipc);
  460.     }
  461.     }
  462. }
  463. #endif /* CRIPPLED_SELECT */
  464.  
  465.  
  466. #ifdef VMS
  467. /*-----------------------------------------------------------------------------
  468.  *    VMS mainloop - Yehavi Bourvine - YEHAVI@VMS.HUJI.AC.IL
  469.  *---------------------------------------------------------------------------*/
  470.  
  471. /*  In VMS there is no decent Select(). hence, we have to loop inside
  472.  *  XGetNextEvent for getting the next X window event. In order to get input
  473.  *  from the master we assign a channel to SYS$INPUT and use AST's in order to
  474.  *  receive data. In order to exit the mainloop, we need to somehow make XNextEvent
  475.  *  return from within the ast. We do this with a XSendEvent() to ourselves !
  476.  *  This needs a window to send the message to, so we create an unmapped window
  477.  *  for this purpose. Event type XClientMessage is perfect for this, but it
  478.  *  appears that such messages come from elsewhere (motif window manager, perhaps ?)
  479.  *  So we need to check fairly carefully that it is the ast event that has been received.
  480.  */
  481.  
  482. #include <iodef.h>
  483. char STDIIN[] = "SYS$INPUT:";
  484. short STDIINchannel, STDIINiosb[4];
  485. struct { short size, type; char *address; } STDIINdesc;
  486. char STDIINbuffer[64];
  487. int status;
  488.  
  489. ast()
  490. {
  491.     int status = sys$qio(0, STDIINchannel, IO$_READVBLK, STDIINiosb, record,
  492.           0, STDIINbuffer, sizeof(STDIINbuffer) - 1, 0, 0, 0, 0);
  493.     if ((status & 0x1) == 0)
  494.     EXIT(status);
  495. }
  496.  
  497. Window message_window;
  498.  
  499. void mainloop()
  500. {
  501.     /* dummy unmapped window for receiving internally-generated terminate
  502.      * messages
  503.      */
  504.     message_window = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 1, 0, 0);
  505.  
  506.     STDIINdesc.size = strlen(STDIIN);
  507.     STDIINdesc.type = 0;
  508.     STDIINdesc.address = STDIIN;
  509.     status = sys$assign(&STDIINdesc, &STDIINchannel, 0, 0, 0);
  510.     if ((status & 0x1) == 0)
  511.     EXIT(status);
  512.     ast();
  513.  
  514.     for (;;) {
  515.     XEvent xe;
  516.     XNextEvent(dpy, &xe);
  517.     if (xe.type == ClientMessage && xe.xclient.window == message_window) {
  518.         if (xe.xclient.message_type == None &&
  519.         xe.xclient.format == 8 &&
  520.         strcmp(xe.xclient.data.b, "die gnuplot die") == 0) {
  521.         FPRINTF((stderr, "quit message from ast\n"));
  522.         return;
  523.         } else {
  524.         FPRINTF((stderr, "Bogus XClientMessage event from window manager ?\n"));
  525.         }
  526.     }
  527.     process_event(&xe);
  528.     }
  529. }
  530.  
  531. #endif /* VMS */
  532.  
  533. /* delete a window / plot */
  534.  
  535. void delete_plot(plot)
  536. plot_struct *plot;
  537. {
  538.     int i;
  539.  
  540.     FPRINTF((stderr, "Delete plot %d\n", plot - plot_array));
  541.  
  542.     for (i = 0; i < plot->ncommands; ++i)
  543.     free(plot->commands[i]);
  544.     plot->ncommands = 0;
  545.  
  546.     if (plot->window) {
  547.     FPRINTF((stderr, "Destroy window 0x%x\n", plot->window));
  548.     XDestroyWindow(dpy, plot->window);
  549.     plot->window = None;
  550.     --windows_open;
  551.     }
  552.     if (plot->pixmap) {
  553.     XFreePixmap(dpy, plot->pixmap);
  554.     plot->pixmap = None;
  555.     }
  556.     /* but preserve geometry */
  557. }
  558.  
  559.  
  560. /* prepare the plot structure */
  561.  
  562. void prepare_plot(plot, term_number)
  563. plot_struct *plot;
  564. int term_number;
  565. {
  566.     int i;
  567.     char *term_name;
  568.  
  569.     for (i = 0; i < plot->ncommands; ++i)
  570.     free(plot->commands[i]);
  571.     plot->ncommands = 0;
  572.  
  573.     if (!plot->posn_flags) {
  574.     /* first time this window has been used - use default or -geometry
  575.      * settings
  576.      */
  577.     plot->posn_flags = gFlags;
  578.     plot->x = gX;
  579.     plot->y = gY;
  580.     plot->width = gW;
  581.     plot->height = gH;
  582.     }
  583.  
  584.     if (!plot->window) {
  585.     plot->window = pr_window(plot->posn_flags, plot->x, plot->y, plot->width, plot->height);
  586.     ++windows_open;
  587.  
  588.     /* append the X11 terminal number (if greater than zero) */
  589.  
  590.     if (term_number) {
  591.         char new_name[60];
  592.         XFetchName(dpy, plot->window, &term_name);
  593.         FPRINTF((stderr, "Window title is %s\n", term_name));
  594.  
  595.         sprintf(new_name, "%.55s%3d", term_name, term_number);
  596.         FPRINTF((stderr, "term_number  is %d\n", term_number));
  597.  
  598.         XStoreName(dpy, plot->window, new_name);
  599.  
  600.         sprintf(new_name, "gplt%3d", term_number);
  601.         XSetIconName(dpy, plot->window, new_name);
  602.     }
  603.     }
  604. /* We don't know that it is the same window as before, so we reset the
  605.  * cursors for all windows and then define the cursor for the active
  606.  * window 
  607.  */
  608.     reset_cursor();
  609.     XDefineCursor(dpy, plot->window, cursor);
  610.  
  611. }
  612.  
  613. /* store a command in a plot structure */
  614.  
  615. void store_command(buffer, plot)
  616. char *buffer;
  617. plot_struct *plot;
  618. {
  619.     char *p;
  620.  
  621.     FPRINTF((stderr, "Store in %d : %s", plot - plot_array, buffer));
  622.  
  623.     if (plot->ncommands >= plot->max_commands) {
  624.     plot->max_commands = plot->max_commands * 2 + 1;
  625.     plot->commands = (plot->commands)
  626.         ? (char **) realloc(plot->commands, plot->max_commands * sizeof(char *))
  627.     : (char **) malloc(sizeof(char *));
  628.     }
  629.     p = (char *) malloc((unsigned) strlen(buffer) + 1);
  630.     if (!plot->commands || !p) {
  631.     fputs("gnuplot: can't get memory. X11 aborted.\n", stderr);
  632.     EXIT(1);
  633.     }
  634.     plot->commands[plot->ncommands++] = strcpy(p, buffer);
  635. }
  636.  
  637. #ifndef VMS
  638. /*-----------------------------------------------------------------------------
  639.  *   record - record new plot from gnuplot inboard X11 driver (Unix)
  640.  *---------------------------------------------------------------------------*/
  641.  
  642. int record()
  643. {
  644.     static plot_struct *plot = plot_array;
  645.  
  646.     while (fgets(buf, Nbuf, X11_ipc)) {
  647.     switch (*buf) {
  648.     case 'G':        /* enter graphics mode */
  649.         {
  650.         int plot_number = atoi(buf + 1);    /* 0 if none specified */
  651.  
  652.         if (plot_number < 0 || plot_number >= MAX_WINDOWS)
  653.             plot_number = 0;
  654.  
  655.         FPRINTF((stderr, "plot for window number %d\n", plot_number));
  656.         plot = plot_array + plot_number;
  657.         prepare_plot(plot, plot_number);
  658.         continue;
  659.         }
  660.     case 'E':        /* leave graphics mode / suspend */
  661.         display(plot);
  662.         return 1;
  663.     case 'R':        /* leave x11 mode */
  664.         reset_cursor();
  665.         return 0;
  666.     default:
  667.         store_command(buf, plot);
  668.         continue;
  669.     }
  670.     }
  671.  
  672.     /* get here if fgets fails */
  673.  
  674. #ifdef OSK
  675.     if (feof(X11_ipc))        /* On OS-9 sometimes while resizing the window,  */
  676.     _cleareof(X11_ipc);    /* and plotting data, the eof or error flag of   */
  677.     if (ferror(X11_ipc))    /* X11_ipc stream gets set, while there is       */
  678.     clearerr(X11_ipc);    /* nothing wrong! Probably a bug in my select()? */
  679. #else
  680.     if (feof(X11_ipc) || ferror(X11_ipc))
  681.     return 0;
  682. #endif /* not OSK */
  683.  
  684.     return 1;
  685. }
  686.  
  687. #else /* VMS */
  688. /*-----------------------------------------------------------------------------
  689.  *   record - record new plot from gnuplot inboard X11 driver (VMS)
  690.  *---------------------------------------------------------------------------*/
  691.  
  692. record()
  693. {
  694.     static plot_struct *plot = plot_array;
  695.  
  696.     int status;
  697.  
  698.     if ((STDIINiosb[0] & 0x1) == 0)
  699.     EXIT(STDIINiosb[0]);
  700.     STDIINbuffer[STDIINiosb[1]] = '\0';
  701.     strcpy(buf, STDIINbuffer);
  702.  
  703.     switch (*buf) {
  704.     case 'G':            /* enter graphics mode */
  705.     {
  706.         int plot_number = atoi(buf + 1);    /* 0 if none specified */
  707.         if (plot_number < 0 || plot_number >= MAX_WINDOWS)
  708.         plot_number = 0;
  709.         FPRINTF((stderr, "plot for window number %d\n", plot_number));
  710.         plot = plot_array + plot_number;
  711.         prepare_plot(plot, plot_number);
  712.         break;
  713.     }
  714.     case 'E':            /* leave graphics mode */
  715.     display(plot);
  716.     break;
  717.     case 'R':            /* exit x11 mode */
  718.     FPRINTF((stderr, "received R - sending ClientMessage\n"));
  719.     reset_cursor();
  720.     sys$cancel(STDIINchannel);
  721.     /* this is ridiculous - cook up an event to ourselves,
  722.      * in order to get the mainloop() out of the XNextEvent() call
  723.      * it seems that window manager can also send clientmessages,
  724.      * so put a checksum into the message
  725.      */
  726.     {
  727.         XClientMessageEvent event;
  728.         event.type = ClientMessage;
  729.         event.send_event = True;
  730.         event.display = dpy;
  731.         event.window = message_window;
  732.         event.message_type = None;
  733.         event.format = 8;
  734.         strcpy(event.data.b, "die gnuplot die");
  735.         XSendEvent(dpy, message_window, False, 0, (XEvent *) & event);
  736.         XFlush(dpy);
  737.     }
  738.     return;            /* no ast */
  739.     default:
  740.     store_command(buf, plot);
  741.     break;
  742.     }
  743.     ast();
  744. }
  745. #endif /* VMS */
  746.  
  747.  
  748. /*-----------------------------------------------------------------------------
  749.  *   display - display a stored plot
  750.  *---------------------------------------------------------------------------*/
  751.  
  752. void display(plot)
  753. plot_struct *plot;
  754. {
  755.     int n, x, y, sw, sl, lt = 0, width, type, point, px, py;
  756.     int user_width = 1;        /* as specified by plot...linewidth */
  757.     char *buffer, *str;
  758.     enum JUSTIFY jmode;
  759.  
  760.     FPRINTF((stderr, "Display %d ; %d commands\n", plot - plot_array, plot->ncommands));
  761.  
  762.     if (plot->ncommands == 0)
  763.     return;
  764.  
  765.     /* set scaling factor between internal driver & window geometry */
  766.     xscale = plot->width / 4096.0;
  767.     yscale = plot->height / 4096.0;
  768.  
  769.     /* initial point sizes, until overridden with P7xxxxyyyy */
  770.     px = (int) (xscale * pointsize);
  771.     py = (int) (yscale * pointsize);
  772.  
  773.     /* create new pixmap & GC */
  774.     if (gc)
  775.     XFreeGC(dpy, gc);
  776.  
  777.     if (!plot->pixmap) {
  778.     FPRINTF((stderr, "Create pixmap %d : %dx%dx%d\n", plot - plot_array, plot->width, plot->height, D));
  779.     plot->pixmap = XCreatePixmap(dpy, root, plot->width, plot->height, D);
  780.     }
  781.  
  782.     gc = XCreateGC(dpy, plot->pixmap, 0, (XGCValues *) 0);
  783.  
  784.     XSetFont(dpy, gc, font->fid);
  785.  
  786.     /* set pixmap background */
  787.     XSetForeground(dpy, gc, colors[0]);
  788.     XFillRectangle(dpy, plot->pixmap, gc, 0, 0, plot->width, plot->height);
  789.     XSetBackground(dpy, gc, colors[0]);
  790.  
  791.     if (!plot->window) {
  792.     plot->window = pr_window(plot->posn_flags, plot->x, plot->y, plot->width, plot->height);
  793.     ++windows_open;
  794.     }
  795.     /* top the window but don't put keyboard or mouse focus into it. */
  796.     if (do_raise)
  797.     XMapRaised(dpy, plot->window);
  798.  
  799.     /* momentarily clear the window first if requested */
  800.     if (Clear) {
  801.     XClearWindow(dpy, plot->window);
  802.     XFlush(dpy);
  803.     }
  804.     /* loop over accumulated commands from inboard driver */
  805.     for (n = 0; n < plot->ncommands; n++) {
  806.     buffer = plot->commands[n];
  807.  
  808.     /*   X11_vector(x,y) - draw vector  */
  809.     if (*buffer == 'V') {
  810.         sscanf(buffer, "V%4d%4d", &x, &y);
  811.         XDrawLine(dpy, plot->pixmap, gc, X(cx), Y(cy), X(x), Y(y));
  812.         cx = x;
  813.         cy = y;
  814.     }
  815.     /*   X11_move(x,y) - move  */
  816.     else if (*buffer == 'M')
  817.         sscanf(buffer, "M%4d%4d", &cx, &cy);
  818.  
  819.     /*   X11_put_text(x,y,str) - draw text   */
  820.     else if (*buffer == 'T') {
  821.         sscanf(buffer, "T%4d%4d", &x, &y);
  822.         str = buffer + 9;
  823.         sl = strlen(str) - 1;
  824.         sw = XTextWidth(font, str, sl);
  825.  
  826.         switch (jmode) {
  827.         case LEFT:
  828.         sw = 0;
  829.         break;
  830.         case CENTRE:
  831.         sw = -sw / 2;
  832.         break;
  833.         case RIGHT:
  834.         sw = -sw;
  835.         break;
  836.         }
  837.  
  838.         XSetForeground(dpy, gc, colors[2]);
  839.         XDrawString(dpy, plot->pixmap, gc, X(x) + sw, Y(y) + vchar / 3, str, sl);
  840.         XSetForeground(dpy, gc, colors[lt + 3]);
  841.     } else if (*buffer == 'F') {    /* fill box */
  842.         int style, xtmp, ytmp, w, h;
  843.  
  844.         if (sscanf(buffer + 1, "%4d%4d%4d%4d%4d", &style, &xtmp, &ytmp, &w, &h) == 5) {
  845.         /* gnuplot has origin at bottom left, but X uses top left
  846.          * There may be an off-by-one (or more) error here.
  847.          * style ignored here for the moment
  848.          */
  849.         ytmp += h;        /* top left corner of rectangle to be filled */
  850.         w *= xscale;
  851.         h *= yscale;
  852.         XSetForeground(dpy, gc, colors[0]);
  853.         XFillRectangle(dpy, plot->pixmap, gc, X(xtmp), Y(ytmp), w, h);
  854.         XSetForeground(dpy, gc, colors[lt + 3]);
  855.         }
  856.     }
  857.     /*   X11_justify_text(mode) - set text justification mode  */
  858.     else if (*buffer == 'J')
  859.         sscanf(buffer, "J%4d", (int *) &jmode);
  860.  
  861.     /*  X11_linewidth(width) - set line width */
  862.     else if (*buffer == 'W')
  863.         sscanf(buffer + 1, "%4d", &user_width);
  864.  
  865.     /*   X11_linetype(type) - set line type  */
  866.     else if (*buffer == 'L') {
  867.         sscanf(buffer, "L%4d", <);
  868.         lt = (lt % 8) + 2;
  869.         /* default width is 0 {which X treats as 1} */
  870.         width = widths[lt] ? user_width * widths[lt] : user_width;
  871.         if (dashes[lt][0]) {
  872.         type = LineOnOffDash;
  873.         XSetDashes(dpy, gc, 0, dashes[lt], strlen(dashes[lt]));
  874.         } else {
  875.         type = LineSolid;
  876.         }
  877.         XSetForeground(dpy, gc, colors[lt + 3]);
  878.         XSetLineAttributes(dpy, gc, width, type, CapButt, JoinBevel);
  879.     }
  880.     /*   X11_point(number) - draw a point */
  881.     else if (*buffer == 'P') {
  882.         /* linux sscanf does not like %1d%4d%4d" with Oxxxxyyyy */
  883.         /* sscanf(buffer, "P%1d%4d%4d", &point, &x, &y); */
  884.         point = buffer[1] - '0';
  885.         sscanf(buffer + 2, "%4d%4d", &x, &y);
  886.         if (point == 7) {
  887.         /* set point size */
  888.         px = (int) (x * xscale * pointsize);
  889.         py = (int) (y * yscale * pointsize);
  890.         } else {
  891.         if (type != LineSolid || width != 0) {    /* select solid line */
  892.             XSetLineAttributes(dpy, gc, 0, LineSolid, CapButt, JoinBevel);
  893.         }
  894.         switch (point) {
  895.         case 0:    /* dot */
  896.             XDrawPoint(dpy, plot->pixmap, gc, X(x), Y(y));
  897.             break;
  898.         case 1:    /* do diamond */
  899.             Diamond[0].x = (short) X(x) - px;
  900.             Diamond[0].y = (short) Y(y);
  901.             Diamond[1].x = (short) px;
  902.             Diamond[1].y = (short) -py;
  903.             Diamond[2].x = (short) px;
  904.             Diamond[2].y = (short) py;
  905.             Diamond[3].x = (short) -px;
  906.             Diamond[3].y = (short) py;
  907.             Diamond[4].x = (short) -px;
  908.             Diamond[4].y = (short) -py;
  909.  
  910.             /*
  911.              * Should really do a check with XMaxRequestSize()
  912.              */
  913.             XDrawLines(dpy, plot->pixmap, gc, Diamond, 5, CoordModePrevious);
  914.             XDrawPoint(dpy, plot->pixmap, gc, X(x), Y(y));
  915.             break;
  916.         case 2:    /* do plus */
  917.             Plus[0].x1 = (short) X(x) - px;
  918.             Plus[0].y1 = (short) Y(y);
  919.             Plus[0].x2 = (short) X(x) + px;
  920.             Plus[0].y2 = (short) Y(y);
  921.             Plus[1].x1 = (short) X(x);
  922.             Plus[1].y1 = (short) Y(y) - py;
  923.             Plus[1].x2 = (short) X(x);
  924.             Plus[1].y2 = (short) Y(y) + py;
  925.  
  926.             XDrawSegments(dpy, plot->pixmap, gc, Plus, 2);
  927.             break;
  928.         case 3:    /* do box */
  929.             XDrawRectangle(dpy, plot->pixmap, gc, X(x) - px, Y(y) - py, (px + px), (py + py));
  930.             XDrawPoint(dpy, plot->pixmap, gc, X(x), Y(y));
  931.             break;
  932.         case 4:    /* do X */
  933.             Cross[0].x1 = (short) X(x) - px;
  934.             Cross[0].y1 = (short) Y(y) - py;
  935.             Cross[0].x2 = (short) X(x) + px;
  936.             Cross[0].y2 = (short) Y(y) + py;
  937.             Cross[1].x1 = (short) X(x) - px;
  938.             Cross[1].y1 = (short) Y(y) + py;
  939.             Cross[1].x2 = (short) X(x) + px;
  940.             Cross[1].y2 = (short) Y(y) - py;
  941.  
  942.             XDrawSegments(dpy, plot->pixmap, gc, Cross, 2);
  943.             break;
  944.         case 5:    /* do triangle */
  945.             {
  946.             short temp_x, temp_y;
  947.  
  948.             temp_x = (short) (1.33 * (double) px + 0.5);
  949.             temp_y = (short) (1.33 * (double) py + 0.5);
  950.  
  951.             Triangle[0].x = (short) X(x);
  952.             Triangle[0].y = (short) Y(y) - temp_y;
  953.             Triangle[1].x = (short) temp_x;
  954.             Triangle[1].y = (short) 2 *py;
  955.             Triangle[2].x = (short) -(2 * temp_x);
  956.             Triangle[2].y = (short) 0;
  957.             Triangle[3].x = (short) temp_x;
  958.             Triangle[3].y = (short) -(2 * py);
  959.  
  960.             XDrawLines(dpy, plot->pixmap, gc, Triangle, 4, CoordModePrevious);
  961.             XDrawPoint(dpy, plot->pixmap, gc, X(x), Y(y));
  962.             }
  963.             break;
  964.         case 6:    /* do star */
  965.             Star[0].x1 = (short) X(x) - px;
  966.             Star[0].y1 = (short) Y(y);
  967.             Star[0].x2 = (short) X(x) + px;
  968.             Star[0].y2 = (short) Y(y);
  969.             Star[1].x1 = (short) X(x);
  970.             Star[1].y1 = (short) Y(y) - py;
  971.             Star[1].x2 = (short) X(x);
  972.             Star[1].y2 = (short) Y(y) + py;
  973.             Star[2].x1 = (short) X(x) - px;
  974.             Star[2].y1 = (short) Y(y) - py;
  975.             Star[2].x2 = (short) X(x) + px;
  976.             Star[2].y2 = (short) Y(y) + py;
  977.             Star[3].x1 = (short) X(x) - px;
  978.             Star[3].y1 = (short) Y(y) + py;
  979.             Star[3].x2 = (short) X(x) + px;
  980.             Star[3].y2 = (short) Y(y) - py;
  981.  
  982.             XDrawSegments(dpy, plot->pixmap, gc, Star, 4);
  983.             break;
  984.         }
  985.         if (type != LineSolid || width != 0) {    /* select solid line */
  986.             XSetLineAttributes(dpy, gc, width, type, CapButt, JoinBevel);
  987.         }
  988.         }
  989.     }
  990.     }
  991.  
  992.     /* set new pixmap as window background */
  993.     XSetWindowBackgroundPixmap(dpy, plot->window, plot->pixmap);
  994.  
  995.     /* trigger exposure of background pixmap */
  996.     XClearWindow(dpy, plot->window);
  997.  
  998. #ifdef EXPORT_SELECTION
  999.     export_graph(plot);
  1000. #endif
  1001.  
  1002.     XFlush(dpy);
  1003. }
  1004.  
  1005. /*---------------------------------------------------------------------------
  1006.  *  reset all cursors (since we dont have a record of the previous terminal #)
  1007.  *---------------------------------------------------------------------------*/
  1008.  
  1009. void reset_cursor()
  1010. {
  1011.     int plot_number;
  1012.     plot_struct *plot = plot_array;
  1013.  
  1014.     for (plot_number = 0, plot = plot_array;
  1015.      plot_number < MAX_WINDOWS;
  1016.      ++plot_number, ++plot) {
  1017.     if (plot->window) {
  1018.         FPRINTF((stderr, "Window for plot %d exists\n", plot_number));
  1019.         XUndefineCursor(dpy, plot->window);;
  1020.     }
  1021.     }
  1022.  
  1023.     FPRINTF((stderr, "Cursors reset\n"));
  1024.     return;
  1025. }
  1026.  
  1027. /*-----------------------------------------------------------------------------
  1028.  *   resize - rescale last plot if window resized
  1029.  *---------------------------------------------------------------------------*/
  1030.  
  1031. plot_struct *find_plot(window)
  1032. Window window;
  1033. {
  1034.     int plot_number;
  1035.     plot_struct *plot = plot_array;
  1036.  
  1037.     for (plot_number = 0, plot = plot_array;
  1038.      plot_number < MAX_WINDOWS;
  1039.      ++plot_number, ++plot) {
  1040.     if (plot->window == window) {
  1041.         FPRINTF((stderr, "Event for plot %d\n", plot_number));
  1042.         return plot;
  1043.     }
  1044.     }
  1045.  
  1046.     FPRINTF((stderr, "Bogus window 0x%x in event !\n", window));
  1047.     return NULL;
  1048. }
  1049.  
  1050. void process_event(event)
  1051. XEvent *event;
  1052. {
  1053.     FPRINTF((stderr, "Event 0x%x\n", event->type));
  1054.  
  1055.     switch (event->type) {
  1056.     case ConfigureNotify:
  1057.     {
  1058.         plot_struct *plot = find_plot(event->xconfigure.window);
  1059.         if (plot) {
  1060.         int w = event->xconfigure.width, h = event->xconfigure.height;
  1061.  
  1062.         /* store settings in case window is closed then recreated */
  1063.         plot->x = event->xconfigure.x;
  1064.         plot->y = event->xconfigure.y;
  1065.         plot->posn_flags = (plot->posn_flags & ~PPosition) | USPosition;
  1066.  
  1067.         if (w > 1 && h > 1 && (w != plot->width || h != plot->height)) {
  1068.             plot->width = w;
  1069.             plot->height = h;
  1070.             plot->posn_flags = (plot->posn_flags & ~PSize) | USSize;
  1071.             if (plot->pixmap) {
  1072.             /* it is the wrong size now */
  1073.             FPRINTF((stderr, "Free pixmap %d\n", 0));
  1074.             XFreePixmap(dpy, plot->pixmap);
  1075.             plot->pixmap = None;
  1076.             }
  1077.             display(plot);
  1078.         }
  1079.         }
  1080.         break;
  1081.     }
  1082.     case KeyPress:
  1083.     if (event->xkey.keycode == q_keycode) {
  1084.         plot_struct *plot = find_plot(event->xkey.window);
  1085.         if (plot)
  1086.         delete_plot(plot);
  1087.     }
  1088.     break;
  1089.     case ClientMessage:
  1090.     if (event->xclient.message_type == WM_PROTOCOLS &&
  1091.         event->xclient.format == 32 &&
  1092.         event->xclient.data.l[0] == WM_DELETE_WINDOW) {
  1093.         plot_struct *plot = find_plot(event->xclient.window);
  1094.         if (plot)
  1095.         delete_plot(plot);
  1096.     }
  1097.     break;
  1098. #ifdef EXPORT_SELECTION
  1099.     case SelectionNotify:
  1100.     case SelectionRequest:
  1101.     handle_selection_event(event);
  1102.     break;
  1103. #endif
  1104.     }
  1105. }
  1106.  
  1107. /*-----------------------------------------------------------------------------
  1108.  *   preset - determine options, open display, create window
  1109.  *---------------------------------------------------------------------------*/
  1110.  
  1111. #define On(v) ( !strcmp(v,"on") || !strcmp(v,"true") || \
  1112.                 !strcmp(v,"On") || !strcmp(v,"True") || \
  1113.                 !strcmp(v,"ON") || !strcmp(v,"TRUE") )
  1114.  
  1115. #define AppDefDir "/usr/lib/X11/app-defaults"
  1116. #ifndef MAXHOSTNAMELEN
  1117. #define MAXHOSTNAMELEN 64
  1118. #endif
  1119.  
  1120. static XrmDatabase dbCmd, dbApp, dbDef, dbEnv, db = (XrmDatabase) 0;
  1121.  
  1122. char *pr_GetR(), *getenv(), *type[20];
  1123. XrmValue value;
  1124.  
  1125. static XrmOptionDescRec options[] = {
  1126.     {"-mono", ".mono", XrmoptionNoArg, (caddr_t) "on"},
  1127.     {"-gray", ".gray", XrmoptionNoArg, (caddr_t) "on"},
  1128.     {"-clear", ".clear", XrmoptionNoArg, (caddr_t) "on"},
  1129.     {"-tvtwm", ".tvtwm", XrmoptionNoArg, (caddr_t) "on"},
  1130.     {"-pointsize", ".pointsize", XrmoptionSepArg, (caddr_t) NULL},
  1131.     {"-display", ".display", XrmoptionSepArg, (caddr_t) NULL},
  1132.     {"-name", ".name", XrmoptionSepArg, (caddr_t) NULL},
  1133.     {"-geometry", "*geometry", XrmoptionSepArg, (caddr_t) NULL},
  1134.     {"-background", "*background", XrmoptionSepArg, (caddr_t) NULL},
  1135.     {"-bg", "*background", XrmoptionSepArg, (caddr_t) NULL},
  1136.     {"-foreground", "*foreground", XrmoptionSepArg, (caddr_t) NULL},
  1137.     {"-fg", "*foreground", XrmoptionSepArg, (caddr_t) NULL},
  1138.     {"-bordercolor", "*bordercolor", XrmoptionSepArg, (caddr_t) NULL},
  1139.     {"-bd", "*bordercolor", XrmoptionSepArg, (caddr_t) NULL},
  1140.     {"-borderwidth", ".borderwidth", XrmoptionSepArg, (caddr_t) NULL},
  1141.     {"-bw", ".borderwidth", XrmoptionSepArg, (caddr_t) NULL},
  1142.     {"-font", "*font", XrmoptionSepArg, (caddr_t) NULL},
  1143.     {"-fn", "*font", XrmoptionSepArg, (caddr_t) NULL},
  1144.     {"-reverse", "*reverseVideo", XrmoptionNoArg, (caddr_t) "on"},
  1145.     {"-rv", "*reverseVideo", XrmoptionNoArg, (caddr_t) "on"},
  1146.     {"+rv", "*reverseVideo", XrmoptionNoArg, (caddr_t) "off"},
  1147.     {"-iconic", "*iconic", XrmoptionNoArg, (caddr_t) "on"},
  1148.     {"-synchronous", "*synchronous", XrmoptionNoArg, (caddr_t) "on"},
  1149.     {"-xnllanguage", "*xnllanguage", XrmoptionSepArg, (caddr_t) NULL},
  1150.     {"-selectionTimeout", "*selectionTimeout", XrmoptionSepArg, (caddr_t) NULL},
  1151.     {"-title", ".title", XrmoptionSepArg, (caddr_t) NULL},
  1152.     {"-xrm", NULL, XrmoptionResArg, (caddr_t) NULL},
  1153.     {"-raise", "*raise", XrmoptionNoArg, (caddr_t) "on"},
  1154.     {"-noraise", "*raise", XrmoptionNoArg, (caddr_t) "off"},
  1155.     {"-persist", "*persist", XrmoptionNoArg, (caddr_t) "on"}
  1156. };
  1157.  
  1158. #define Nopt (sizeof(options) / sizeof(options[0]))
  1159.  
  1160. void preset(argc, argv)
  1161. int argc;
  1162. char *argv[];
  1163. {
  1164.     int Argc = argc;
  1165.     char **Argv = argv;
  1166.  
  1167. #ifdef VMS
  1168.     char *ldisplay = (char *) 0;
  1169. #else
  1170.     char *ldisplay = getenv("DISPLAY");
  1171. #endif
  1172.     char *home = getenv("HOME");
  1173.     char *server_defaults, *env, buffer[256];
  1174.  
  1175.     /* avoid bus error when env vars are not set */
  1176.     if (ldisplay == NULL)
  1177.     ldisplay = "";
  1178.     if (home == NULL)
  1179.     home = "";
  1180.  
  1181. /*---set to ignore ^C and ^Z----------------------------------------------*/
  1182.  
  1183.     signal(SIGINT, SIG_IGN);
  1184. #ifdef SIGTSTP
  1185.     signal(SIGTSTP, SIG_IGN);
  1186. #endif
  1187.  
  1188. /*---prescan arguments for "-name"----------------------------------------*/
  1189.  
  1190.     while (++Argv, --Argc > 0) {
  1191.     if (!strcmp(*Argv, "-name") && Argc > 1) {
  1192.         safe_strncpy(Name, Argv[1], sizeof(Name));
  1193.         safe_strncpy(Class, Argv[1], sizeof(Class));
  1194.         if (Class[0] >= 'a' && Class[0] <= 'z')
  1195.         Class[0] -= 0x20;
  1196.     }
  1197.     }
  1198.     Argc = argc;
  1199.     Argv = argv;
  1200.  
  1201. /*---parse command line---------------------------------------------------*/
  1202.  
  1203.     XrmInitialize();
  1204.     XrmParseCommand(&dbCmd, options, Nopt, Name, &Argc, Argv);
  1205.     if (Argc > 1) {
  1206.     fprintf(stderr, "\n\
  1207. gnuplot: bad option: %s\n\
  1208. gnuplot: X11 aborted.\n", Argv[1]);
  1209.     EXIT(1);
  1210.     }
  1211.     if (pr_GetR(dbCmd, ".display"))
  1212.     ldisplay = (char *) value.addr;
  1213.  
  1214. /*---open display---------------------------------------------------------*/
  1215.  
  1216.     dpy = XOpenDisplay(ldisplay);
  1217.     if (!dpy) {
  1218.     fprintf(stderr, "\n\
  1219. gnuplot: unable to open display '%s'\n\
  1220. gnuplot: X11 aborted.\n", ldisplay);
  1221.     EXIT(1);
  1222.     }
  1223.     scr = DefaultScreen(dpy);
  1224.     vis = DefaultVisual(dpy, scr);
  1225.     D = DefaultDepth(dpy, scr);
  1226.     root = DefaultRootWindow(dpy);
  1227.     server_defaults = XResourceManagerString(dpy);
  1228.  
  1229. /*---get symcode for key q ---*/
  1230.  
  1231.     q_keycode = XKeysymToKeycode(dpy, XK_q);
  1232.  
  1233. /**** atoms we will need later ****/
  1234.  
  1235.     WM_PROTOCOLS = XInternAtom(dpy, "WM_PROTOCOLS", False);
  1236.     WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  1237.  
  1238.  
  1239. /*---get application defaults--(subset of Xt processing)------------------*/
  1240.  
  1241. #ifdef VMS
  1242.     strcpy(buffer, "DECW$USER_DEFAULTS:GNUPLOT_X11.INI");
  1243. #else
  1244. # ifdef OS2
  1245. /* for Xfree86 ... */
  1246.     {
  1247.     char *appdefdir = "XFree86/lib/X11/app-defaults";
  1248.     char *xroot = getenv("X11ROOT");
  1249.     sprintf(buffer, "%s/%s/%s", xroot, appdefdir, "Gnuplot");
  1250.     }
  1251. # else
  1252.     sprintf(buffer, "%s/%s", AppDefDir, "Gnuplot");
  1253. # endif /* !OS2 */
  1254. #endif /* !VMS */
  1255.  
  1256.     dbApp = XrmGetFileDatabase(buffer);
  1257.     XrmMergeDatabases(dbApp, &db);
  1258.  
  1259. /*---get server or ~/.Xdefaults-------------------------------------------*/
  1260.  
  1261.     if (server_defaults)
  1262.     dbDef = XrmGetStringDatabase(server_defaults);
  1263.     else {
  1264. #ifdef VMS
  1265.     strcpy(buffer, "DECW$USER_DEFAULTS:DECW$XDEFAULTS.DAT");
  1266. #else
  1267.     sprintf(buffer, "%s/.Xdefaults", home);
  1268. #endif
  1269.     dbDef = XrmGetFileDatabase(buffer);
  1270.     }
  1271.     XrmMergeDatabases(dbDef, &db);
  1272.  
  1273. /*---get XENVIRONMENT or  ~/.Xdefaults-hostname---------------------------*/
  1274.  
  1275. #ifndef VMS
  1276.     if ((env = getenv("XENVIRONMENT")) != NULL)
  1277.     dbEnv = XrmGetFileDatabase(env);
  1278.     else {
  1279.     char *p = NULL, host[MAXHOSTNAMELEN];
  1280.  
  1281.     if (GP_SYSTEMINFO(host) < 0) {
  1282.         fprintf(stderr, "gnuplot: %s failed. X11 aborted.\n", SYSINFO_METHOD);
  1283.         EXIT(1);
  1284.     }
  1285.     if ((p = strchr(host, '.')) != NULL)
  1286.         *p = '\0';
  1287.     sprintf(buffer, "%s/.Xdefaults-%s", home, host);
  1288.     dbEnv = XrmGetFileDatabase(buffer);
  1289.     }
  1290.     XrmMergeDatabases(dbEnv, &db);
  1291. #endif /* not VMS */
  1292.  
  1293. /*---merge command line options-------------------------------------------*/
  1294.  
  1295.     XrmMergeDatabases(dbCmd, &db);
  1296.  
  1297. /*---set geometry, font, colors, line widths, dash styles, point size-----*/
  1298.  
  1299.     pr_geometry();
  1300.     pr_font();
  1301.     pr_color();
  1302.     pr_width();
  1303.     pr_dashes();
  1304.     pr_pointsize();
  1305.     pr_raise();
  1306.     pr_persist();
  1307. }
  1308.  
  1309. /*-----------------------------------------------------------------------------
  1310.  *   pr_GetR - get resource from database using "-name" option (if any)
  1311.  *---------------------------------------------------------------------------*/
  1312.  
  1313. char *
  1314.  pr_GetR(xrdb, resource)
  1315. XrmDatabase xrdb;
  1316. char *resource;
  1317. {
  1318.     char name[128], class[128], *rc;
  1319.  
  1320.     strcpy(name, Name);
  1321.     strcat(name, resource);
  1322.     strcpy(class, Class);
  1323.     strcat(class, resource);
  1324.     rc = XrmGetResource(xrdb, name, class, type, &value)
  1325.     ? (char *) value.addr
  1326.     : (char *) 0;
  1327.     return (rc);
  1328. }
  1329.  
  1330. /*-----------------------------------------------------------------------------
  1331.  *   pr_color - determine color values
  1332.  *---------------------------------------------------------------------------*/
  1333.  
  1334. char color_keys[Ncolors][30] = {
  1335.     "background", "bordercolor", "text", "border", "axis",
  1336.     "line1", "line2", "line3", "line4",
  1337.     "line5", "line6", "line7", "line8"
  1338. };
  1339. char color_values[Ncolors][30] = {
  1340.     "white", "black", "black", "black", "black",
  1341.     "red", "green", "blue", "magenta",
  1342.     "cyan", "sienna", "orange", "coral"
  1343. };
  1344. char gray_values[Ncolors][30] = {
  1345.     "black", "white", "white", "gray50", "gray50",
  1346.     "gray100", "gray60", "gray80", "gray40",
  1347.     "gray90", "gray50", "gray70", "gray30"
  1348. };
  1349.  
  1350. void pr_color()
  1351. {
  1352.     unsigned long black = BlackPixel(dpy, scr), white = WhitePixel(dpy, scr);
  1353.     char option[20], color[30], *v, *ctype;
  1354.     XColor xcolor;
  1355.     Colormap cmap;
  1356.     double intensity = -1;
  1357.     int n;
  1358.  
  1359.     pr_GetR(db, ".mono") && On(value.addr) && Mono++;
  1360.     pr_GetR(db, ".gray") && On(value.addr) && Gray++;
  1361.     pr_GetR(db, ".reverseVideo") && On(value.addr) && Rv++;
  1362.  
  1363.     if (!Gray && (vis->class == GrayScale || vis->class == StaticGray))
  1364.     Mono++;
  1365.  
  1366.     if (!Mono) {
  1367.     cmap = DefaultColormap(dpy, scr);
  1368.     ctype = (Gray) ? "Gray" : "Color";
  1369.  
  1370.     for (n = 0; n < Ncolors; n++) {
  1371.         strcpy(option, ".");
  1372.         strcat(option, color_keys[n]);
  1373.         (n > 1) && strcat(option, ctype);
  1374.         v = pr_GetR(db, option)
  1375.         ? (char *) value.addr
  1376.         : ((Gray) ? gray_values[n] : color_values[n]);
  1377.  
  1378.         if (sscanf(v, "%30[^,],%lf", color, &intensity) == 2) {
  1379.         if (intensity < 0 || intensity > 1) {
  1380.             fprintf(stderr, "\ngnuplot: invalid color intensity in '%s'\n",
  1381.                 color);
  1382.             intensity = 1;
  1383.         }
  1384.         } else {
  1385.         strcpy(color, v);
  1386.         intensity = 1;
  1387.         }
  1388.  
  1389.         if (!XParseColor(dpy, cmap, color, &xcolor)) {
  1390.         fprintf(stderr, "\ngnuplot: unable to parse '%s'. Using black.\n",
  1391.             color);
  1392.         colors[n] = black;
  1393.         } else {
  1394.         xcolor.red *= intensity;
  1395.         xcolor.green *= intensity;
  1396.         xcolor.blue *= intensity;
  1397.         if (XAllocColor(dpy, cmap, &xcolor)) {
  1398.             colors[n] = xcolor.pixel;
  1399.         } else {
  1400.             fprintf(stderr, "\ngnuplot: can't allocate '%s'. Using black.\n",
  1401.                 v);
  1402.             colors[n] = black;
  1403.         }
  1404.         }
  1405.     }
  1406.     } else {
  1407.     colors[0] = (Rv) ? black : white;
  1408.     for (n = 1; n < Ncolors; n++)
  1409.         colors[n] = (Rv) ? white : black;
  1410.     }
  1411. }
  1412.  
  1413. /*-----------------------------------------------------------------------------
  1414.  *   pr_dashes - determine line dash styles 
  1415.  *---------------------------------------------------------------------------*/
  1416.  
  1417. char dash_keys[Ndashes][10] = {
  1418.     "border", "axis",
  1419.     "line1", "line2", "line3", "line4", "line5", "line6", "line7", "line8"
  1420. };
  1421.  
  1422. char dash_mono[Ndashes][10] = {
  1423.     "0", "16",
  1424.     "0", "42", "13", "44", "15", "4441", "42", "13"
  1425. };
  1426.  
  1427. char dash_color[Ndashes][10] = {
  1428.     "0", "16",
  1429.     "0", "0", "0", "0", "0", "0", "0", "0"
  1430. };
  1431.  
  1432. void pr_dashes()
  1433. {
  1434.     int n, j, l, ok;
  1435.     char option[20], *v;
  1436.  
  1437.     for (n = 0; n < Ndashes; n++) {
  1438.     strcpy(option, ".");
  1439.     strcat(option, dash_keys[n]);
  1440.     strcat(option, "Dashes");
  1441.     v = pr_GetR(db, option)
  1442.         ? (char *) value.addr
  1443.         : ((Mono) ? dash_mono[n] : dash_color[n]);
  1444.     l = strlen(v);
  1445.     if (l == 1 && *v == '0') {
  1446.         dashes[n][0] = (unsigned char) 0;
  1447.         continue;
  1448.     }
  1449.     for (ok = 0, j = 0; j < l; j++) {
  1450.         v[j] >= '1' && v[j] <= '9' && ok++;
  1451.     }
  1452.     if (ok != l || (ok != 2 && ok != 4)) {
  1453.         fprintf(stderr, "gnuplot: illegal dashes value %s:%s\n", option, v);
  1454.         dashes[n][0] = (unsigned char) 0;
  1455.         continue;
  1456.     }
  1457.     for (j = 0; j < l; j++) {
  1458.         dashes[n][j] = (unsigned char) (v[j] - '0');
  1459.     }
  1460.     dashes[n][l] = (unsigned char) 0;
  1461.     }
  1462. }
  1463.  
  1464. /*-----------------------------------------------------------------------------
  1465.  *   pr_font - determine font          
  1466.  *---------------------------------------------------------------------------*/
  1467.  
  1468. void pr_font()
  1469. {
  1470.     char *fontname = pr_GetR(db, ".font");
  1471.  
  1472.     if (!fontname)
  1473.     fontname = FallbackFont;
  1474.     font = XLoadQueryFont(dpy, fontname);
  1475.     if (!font) {
  1476.     fprintf(stderr, "\ngnuplot: can't load font '%s'\n", fontname);
  1477.     fprintf(stderr, "gnuplot: using font '%s' instead.\n", FallbackFont);
  1478.     font = XLoadQueryFont(dpy, FallbackFont);
  1479.     if (!font) {
  1480.         fprintf(stderr, "\
  1481. gnuplot: can't load font '%s'\n\
  1482. gnuplot: no useable font - X11 aborted.\n", FallbackFont);
  1483.         EXIT(1);
  1484.     }
  1485.     }
  1486.     vchar = font->ascent + font->descent;
  1487. }
  1488.  
  1489. /*-----------------------------------------------------------------------------
  1490.  *   pr_geometry - determine window geometry      
  1491.  *---------------------------------------------------------------------------*/
  1492.  
  1493. void pr_geometry()
  1494. {
  1495.     char *geometry = pr_GetR(db, ".geometry");
  1496.     int x, y, flags;
  1497.     unsigned int w, h;
  1498.  
  1499.     if (geometry) {
  1500.     flags = XParseGeometry(geometry, &x, &y, &w, &h);
  1501.     if (flags & WidthValue)
  1502.         gW = w;
  1503.     if (flags & HeightValue)
  1504.         gH = h;
  1505.     if (flags & (WidthValue | HeightValue))
  1506.         gFlags = (gFlags & ~PSize) | USSize;
  1507.  
  1508.     if (flags & XValue)
  1509.         gX = (flags & XNegative) ? x + DisplayWidth(dpy, scr) - gW - BorderWidth * 2 : x;
  1510.  
  1511.     if (flags & YValue)
  1512.         gY = (flags & YNegative) ? y + DisplayHeight(dpy, scr) - gH - BorderWidth * 2 : y;
  1513.  
  1514.     if (flags & (XValue | YValue))
  1515.         gFlags = (gFlags & ~PPosition) | USPosition;
  1516.     }
  1517. }
  1518.  
  1519. /*-----------------------------------------------------------------------------
  1520.  *   pr_pointsize - determine size of points for 'points' plotting style
  1521.  *---------------------------------------------------------------------------*/
  1522.  
  1523. void pr_pointsize()
  1524. {
  1525.     if (pr_GetR(db, ".pointsize")) {
  1526.     if (sscanf((char *) value.addr, "%lf", &pointsize) == 1) {
  1527.         if (pointsize <= 0 || pointsize > 10) {
  1528.         fprintf(stderr, "\ngnuplot: invalid pointsize '%s'\n", value.addr);
  1529.         pointsize = 1;
  1530.         }
  1531.     } else {
  1532.         fprintf(stderr, "\ngnuplot: invalid pointsize '%s'\n", value.addr);
  1533.         pointsize = 1;
  1534.     }
  1535.     } else {
  1536.     pointsize = 1;
  1537.     }
  1538. }
  1539.  
  1540. /*-----------------------------------------------------------------------------
  1541.  *   pr_width - determine line width values
  1542.  *---------------------------------------------------------------------------*/
  1543.  
  1544. char width_keys[Nwidths][30] = {
  1545.     "border", "axis",
  1546.     "line1", "line2", "line3", "line4", "line5", "line6", "line7", "line8"
  1547. };
  1548.  
  1549. void pr_width()
  1550. {
  1551.     int n;
  1552.     char option[20], *v;
  1553.  
  1554.     for (n = 0; n < Nwidths; n++) {
  1555.     strcpy(option, ".");
  1556.     strcat(option, width_keys[n]);
  1557.     strcat(option, "Width");
  1558.     if ((v = pr_GetR(db, option)) != NULL) {
  1559.         if (*v < '0' || *v > '4' || strlen(v) > 1)
  1560.         fprintf(stderr, "gnuplot: illegal width value %s:%s\n", option, v);
  1561.         else
  1562.         widths[n] = (unsigned int) atoi(v);
  1563.     }
  1564.     }
  1565. }
  1566.  
  1567. /*-----------------------------------------------------------------------------
  1568.  *   pr_window - create window 
  1569.  *---------------------------------------------------------------------------*/
  1570.  
  1571. Window pr_window(flags, x, y, width, height)
  1572. unsigned int flags;
  1573. int x, y;
  1574. unsigned int width, height;
  1575. {
  1576.     char *title = pr_GetR(db, ".title");
  1577.     static XSizeHints hints;
  1578.     int Tvtwm = 0;
  1579.  
  1580.     Window win = XCreateSimpleWindow(dpy, root, x, y, width, height, BorderWidth,
  1581.                      colors[1], colors[0]);
  1582.  
  1583.     /* ask ICCCM-compliant window manager to tell us when close window
  1584.      * has been chosen, rather than just killing us
  1585.      */
  1586.  
  1587.     XChangeProperty(dpy, win, WM_PROTOCOLS, XA_ATOM, 32, PropModeReplace,
  1588.             (unsigned char *) &WM_DELETE_WINDOW, 1);
  1589.  
  1590.     pr_GetR(db, ".clear") && On(value.addr) && Clear++;
  1591.     pr_GetR(db, ".tvtwm") && On(value.addr) && Tvtwm++;
  1592.  
  1593.     if (!Tvtwm) {
  1594.     hints.flags = flags;
  1595.     } else {
  1596.     hints.flags = (flags & ~USPosition) | PPosition;    /* ? */
  1597.     }
  1598.     hints.x = gX;
  1599.     hints.y = gY;
  1600.     hints.width = width;
  1601.     hints.height = height;
  1602.  
  1603.     XSetNormalHints(dpy, win, &hints);
  1604.  
  1605.     if (pr_GetR(db, ".iconic") && On(value.addr)) {
  1606.     XWMHints wmh;
  1607.  
  1608.     wmh.flags = StateHint;
  1609.     wmh.initial_state = IconicState;
  1610.     XSetWMHints(dpy, win, &wmh);
  1611.     }
  1612.     XStoreName(dpy, win, ((title) ? title : Class));
  1613.  
  1614.     XSelectInput(dpy, win, KeyPressMask | StructureNotifyMask);
  1615.     XMapWindow(dpy, win);
  1616.  
  1617.     return win;
  1618. }
  1619.  
  1620.  
  1621. /***** pr_raise ***/
  1622. void pr_raise()
  1623. {
  1624.     if (pr_GetR(db, ".raise"))
  1625.     do_raise = (On(value.addr));
  1626. }
  1627.  
  1628.  
  1629. void pr_persist()
  1630. {
  1631.     if (pr_GetR(db, ".persist"))
  1632.     persist = (On(value.addr));
  1633. }
  1634.  
  1635. /************ code to handle selection export *********************/
  1636.  
  1637. #ifdef EXPORT_SELECTION
  1638.  
  1639. /* bit of a bodge, but ... */
  1640. static struct plot_struct *exported_plot;
  1641.  
  1642. void export_graph(plot)
  1643. struct plot_struct *plot;
  1644. {
  1645.     FPRINTF((stderr, "export_graph(0x%x)\n", plot));
  1646.  
  1647.     XSetSelectionOwner(dpy, EXPORT_SELECTION, plot->window, CurrentTime);
  1648.     /* to check we have selection, we would have to do a
  1649.      * GetSelectionOwner(), but if it failed, it failed - no big deal
  1650.      */
  1651.     exported_plot = plot;
  1652. }
  1653.  
  1654. void handle_selection_event(event)
  1655. XEvent *event;
  1656. {
  1657.     switch (event->type) {
  1658.     case SelectionRequest:
  1659.     {
  1660.         XEvent reply;
  1661.  
  1662.         static Atom XA_TARGETS = (Atom) 0;
  1663.         if (XA_TARGETS == 0)
  1664.         XA_TARGETS = XInternAtom(dpy, "TARGETS", False);
  1665.  
  1666.         reply.type = SelectionNotify;
  1667.         reply.xselection.send_event = True;
  1668.         reply.xselection.display = event->xselectionrequest.display;
  1669.         reply.xselection.requestor = event->xselectionrequest.requestor;
  1670.         reply.xselection.selection = event->xselectionrequest.selection;
  1671.         reply.xselection.target = event->xselectionrequest.target;
  1672.         reply.xselection.property = event->xselectionrequest.property;
  1673.         reply.xselection.time = event->xselectionrequest.time;
  1674.  
  1675.         FPRINTF((stderr, "selection request\n"));
  1676.  
  1677.         if (reply.xselection.target == XA_TARGETS) {
  1678.         static Atom targets[] =    {XA_PIXMAP, XA_COLORMAP};
  1679.  
  1680.         FPRINTF((stderr, "Targets request from %d\n", reply.xselection.requestor));
  1681.  
  1682.         XChangeProperty(dpy, reply.xselection.requestor,
  1683.                 reply.xselection.property, reply.xselection.target, 32, PropModeReplace,
  1684.                 (unsigned char *) targets, 2);
  1685.         } else if (reply.xselection.target == XA_COLORMAP) {
  1686.         Colormap cmap = DefaultColormap(dpy, 0);
  1687.  
  1688.         FPRINTF((stderr, "colormap request from %d\n", reply.xselection.requestor));
  1689.  
  1690.         XChangeProperty(dpy, reply.xselection.requestor,
  1691.                 reply.xselection.property, reply.xselection.target, 32, PropModeReplace,
  1692.                 (unsigned char *) &cmap, 1);
  1693.         } else if (reply.xselection.target == XA_PIXMAP) {
  1694.  
  1695.         FPRINTF((stderr, "pixmap request from %d\n", reply.xselection.requestor));
  1696.  
  1697.         XChangeProperty(dpy, reply.xselection.requestor,
  1698.                 reply.xselection.property, reply.xselection.target, 32, PropModeReplace,
  1699.               (unsigned char *) &(exported_plot->pixmap), 1);
  1700.         } else {
  1701.         reply.xselection.property = None;
  1702.         }
  1703.  
  1704.         XSendEvent(dpy, reply.xselection.requestor, False, 0L, &reply);
  1705.         /* we never block on XNextEvent(), so must flush manually
  1706.          * (took me *ages* to find this out !)
  1707.          */
  1708.  
  1709.         XFlush(dpy);
  1710.     }
  1711.     break;
  1712.     }
  1713. }
  1714.  
  1715. #endif /* EXPORT_SELECTION */
  1716.